package org.springmvc.context;

import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import org.springmvc.constant.Constants;
import org.springmvc.stereotype.Controller;
import org.springmvc.web.bind.annotation.RequestMapping;
import org.springmvc.web.method.HandlerMethod;
import org.springmvc.web.servlet.HandlerAdapter;
import org.springmvc.web.servlet.HandlerMapping;
import org.springmvc.web.servlet.mvc.method.RequestMappingInfo;

import java.io.File;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author marin
 * @version 1.0
 * @date 2025/9/2 20:53
 * @desc spring的Ioc容器，spring的上下文
 */
@SuppressWarnings("all")
public class ApplicationContext {

    //存储bean对象
    private static Map<String,Object> beanMap = new HashMap<String,Object>();

    public ApplicationContext(String configLocation) {
        try {
            //读取配置文件信息，进行xml的解析
            SAXReader reader = new SAXReader();
            Document document = reader.read(new File(configLocation));
            //获取扫描包节点
            Element componentScanElement = (Element)document.selectSingleNode("beans/component-scan");
            //获取视图解析器节点
            Element viewResolverElement = (Element)document.selectSingleNode("beans/bean");
            //获取拦截器节点
            Element interceptorsElement = (Element)document.selectSingleNode("beans/interceptors");
            //组件扫描
            Map<RequestMappingInfo, HandlerMethod> handlerMethodMap = componentScan(componentScanElement);
            //创建视图解析器
            createViewResolver(viewResolverElement);
            //创建拦截器
            createInterceptors(interceptorsElement);
            //创建RequestMappingHandlerMapping
            createHandlerMapping(Constants.DEFAULT_PACKAGE,handlerMethodMap);
            //创建RequestMappingHandlerAdapter
            createHHandlerAdapter(Constants.DEFAULT_PACKAGE);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 初始化处理器适配器
     * @param defaultPackage
     * @throws ClassNotFoundException
     * @throws InstantiationException
     * @throws IllegalAccessException
     */
    private void createHHandlerAdapter(String defaultPackage) throws ClassNotFoundException, InstantiationException, IllegalAccessException {
        //获取绝对路径
        String defaultPath = defaultPackage.replace(".", File.separator);
        String absolutePath = Thread.currentThread().getContextClassLoader().getResource(defaultPath).getPath();
        for (File file : new File(absolutePath).listFiles()) {
            String fileName = file.getName();
            String className = fileName.substring(0, fileName.lastIndexOf("."));
            String classPath = defaultPackage + "." + className;
            Class<?> aClass = Class.forName(classPath);
            //只有实现了HandlerAdapter接口才可以创建
            if (HandlerAdapter.class.isAssignableFrom(aClass)){
                Object instance = aClass.newInstance();
                beanMap.put(Constants.HANDLER_ADAPTER, instance);
            }
        }
    }

    /**
     * 初始化处理器映射器
     * @param defaultPackage
     * @throws ClassNotFoundException
     * @throws InstantiationException
     * @throws IllegalAccessException
     */
    private void createHandlerMapping(String defaultPackage,Map<RequestMappingInfo, HandlerMethod> handlerMethodMap) throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {
        //获取绝对路径
        String defaultPath = defaultPackage.replace(".", File.separator);
        String absolutePath = Thread.currentThread().getContextClassLoader().getResource(defaultPath).getPath();
        for (File file : new File(absolutePath).listFiles()) {
            String fileName = file.getName();
            String className = fileName.substring(0, fileName.lastIndexOf("."));
            String classPath = defaultPackage + "." + className;
            Class<?> aClass = Class.forName(classPath);
            //只有实现了HandlerMapping接口才可以创建
            if (HandlerMapping.class.isAssignableFrom(aClass)){
                Constructor<?> constructor = aClass.getConstructor(Map.class);
                Object instance = constructor.newInstance(handlerMethodMap);
                beanMap.put(Constants.HANDLER_MAPPING, instance);
            }
        }
    }

    /**
     * 初始化拦截器
     * @param interceptorsElement
     * @throws ClassNotFoundException
     * @throws InstantiationException
     * @throws IllegalAccessException
     */
    private void createInterceptors(Element interceptorsElement) throws ClassNotFoundException, InstantiationException, IllegalAccessException {
        //拦截器都是按顺序放入，创建list集合进行存储
        List<Object> interceptors = new ArrayList<Object>();
        List<Element> elements = interceptorsElement.elements(Constants.ATTRIBUTE_BEAN);
        for (Element element : elements) {
            String classPath= element.attributeValue(Constants.BEAN_CLASS);
            Class<?> aClass = Class.forName(classPath);
            Object instance = aClass.newInstance();
            interceptors.add(instance);
        }
        beanMap.put(Constants.INTERCEPTORS, interceptors);
    }

    /**
     * 初始化视图解析器对象
     * @param viewResolverElement
     */
    private void createViewResolver(Element viewResolverElement) throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchFieldException, NoSuchMethodException, InvocationTargetException {
        String classPath = viewResolverElement.attributeValue(Constants.BEAN_CLASS);
        Class<?> aClass = Class.forName(classPath);
        Object instance = aClass.newInstance();
        //属性赋值
        List<Element> elements = viewResolverElement.elements(Constants.ATTRIBUTE_PROPERTY);
        for (Element element : elements) {
            String propertyName= element.attributeValue(Constants.BEAN_NAME);
            String propertyValue= element.attributeValue(Constants.BEAN_VALUE);
            Field field = aClass.getDeclaredField(propertyName);
            String setMethodName = "set" + toUpperCaseFirstLetter(propertyName);
            Method method = aClass.getMethod(setMethodName, field.getType());
            method.invoke(instance,propertyValue);
        }
        //获取简单的类名
        beanMap.put(Constants.VIEW_RESOLVER, instance);
    }

    /**
     * 初始化被扫描的包下的文件
     * @param componentScanElement
     */
    private Map<RequestMappingInfo, HandlerMethod> componentScan(Element componentScanElement) throws ClassNotFoundException, InstantiationException, IllegalAccessException {
        //存储请求信息和映射的处理器方法
        Map<RequestMappingInfo, HandlerMethod> handlerMethods = new HashMap<>();
        String basePackage = componentScanElement.attributeValue(Constants.BASE_PACKAGE);
        String basePackagePath = basePackage.replace(".", File.separator);
        String absolutePath = Thread.currentThread().getContextClassLoader().getResource(basePackagePath).getPath();
        //将该路径下的文件进行遍历
        File[] files = new File(absolutePath).listFiles();
        for (File file : files) {
            String fileName = file.getName();
            if (fileName.endsWith(Constants.COMMON_CLASS)){//判断是否为.class结尾的文件
                String prefixClassName = fileName.substring(0, fileName.lastIndexOf("."));
                String classPath = basePackage +"."+prefixClassName;
                Class<?> aClass = Class.forName(classPath);
                //如果类上由@Controller注解，就创建该对象，将其放入Ioc容器中，即map集合中
                if (aClass.isAnnotationPresent(Controller.class)) {
                    Object instance = aClass.newInstance();
                    beanMap.put(toLowerCaseFirstLetter(prefixClassName), instance);

                    Method[] methods = aClass.getMethods();
                    for (Method method : methods) {
                        //判断是否由@requestrMapping注解
                        if (method.isAnnotationPresent(RequestMapping.class)){
                            RequestMapping requestMapping = method.getAnnotation(RequestMapping.class);
                            //获取请求uri，请求方式，然后将其关联handlermethod对象放入map集合中
                            RequestMappingInfo requestMappingInfo = new RequestMappingInfo();
                            requestMappingInfo.setRequestMappingPattern(requestMapping.value());
                            requestMappingInfo.setMethod(requestMapping.method().toString());
                            HandlerMethod handlerMethod = new HandlerMethod(instance, method);
                            handlerMethods.put(requestMappingInfo,handlerMethod);
                        }
                    }
                }
            }
        }
        return handlerMethods;
    }


    /**
     * 根据beanName获取bean对象
     * @param beanName
     * @return
     */
    public Object getBean(String beanName) {
        return beanMap.get(beanName);
    }

    // 将第一个字母转小写
    private static String toLowerCaseFirstLetter(String str) {
        if (str == null || str.isEmpty()) {
            return str; // 空串或 null 直接返回
        }
        char firstChar = str.charAt(0);
        if (Character.isLowerCase(firstChar)) {
            return str; // 已经是小写就直接返回
        }
        return Character.toLowerCase(firstChar) + str.substring(1);
    }

    // 将第一个字母转大写
    private static String toUpperCaseFirstLetter(String str) {
        if (str == null || str.isEmpty()) {
            return str;
        }
        char firstChar = str.charAt(0);
        if (Character.isUpperCase(firstChar)) {
            return str;
        }
        return Character.toUpperCase(firstChar) + str.substring(1);
    }
}
